/*
 * main_dll.cpp
 *
 *  Created on: 21.12.2012
 *      Author: aska
 */
#include "main_dll.h"
using namespace std;

hopper_device * hopper_device_inst;
HINSTANCE hopper_dll_handle;

__declspec(dllexport) BOOL WINAPI __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	switch (fdwReason)
	{
	case DLL_PROCESS_ATTACH:
		/* Code path executed when DLL is loaded into a process's address space. */
		printf("DLL_PROCESS_ATTACH\n");
		hopper_dll_handle = hinstDLL;
		break;
	case DLL_THREAD_ATTACH:
		/* Code path executed when a new thread is created within the process. */
		printf("DLL_THREAD_ATTACH\n");
		break;
	case DLL_THREAD_DETACH:
		/* Code path executed when a thread within the process has exited *cleanly*. */
		printf("DLL_THREAD_DETACH\n");
		break;
	case DLL_PROCESS_DETACH:
		printf("DLL_PROCESS_DETACH\n");
		/* Code path executed when DLL is unloaded from a process's address space. */
		break;
	}
	return TRUE;
}

/*__declspec(dllexport) int __stdcall door_control_dev_if_mode(int mode)
{
	int ret_val = 0;
	ret_val = 1;
	return ret_val;
}*/



hopper_device::hopper_device()
{
	char log_str[63];
	char log_file_name_Logs[127];
	GetModuleFileName(hopper_dll_handle, log_file_path, 255);
	//printf("str_path_to_exe %s\n", log_file_path);
	char * substr_occ;
	substr_occ = strrchr(log_file_path, '/');
	if (substr_occ == NULL)
		substr_occ = strrchr(log_file_path, '\\');
	if (substr_occ != NULL)
	{
		*(substr_occ + 1) = '\0';
		//printf("path for log file: %s\n", log_file_path);
	}
	else
	{
		log_file_path[0] = '\0';
		printf("path not found, use empty string as path for log file\n");
	}
	ser_port_No = 0;
	d2xx_dll_is_loaded = 0;
	d2xx_opened = 0;
	ft_handle_opened = 0;
	serial_is_opened = 0;
	dev_interface_mode = 1;
	ft_LocId = 0;
	baud = 9600;
	log_file_year_day_prev = 0;
	log_file_year_day_pres = 0;
	time_t rawtime;
	struct tm * timeinfo;
	time ( &rawtime );
	timeinfo = localtime ( &rawtime );
	log_file_year_day_prev = log_file_year_day_pres;
	//log_file_year_day_pres = timeinfo->tm_yday;
	log_file_year_day_pres = timeinfo->tm_mday;
	//sprintf(log_file_name, "%shopper_log_%4d_%02d_%02d.log", log_file_path, timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday);
	sprintf(log_file_name, "%sLogs/hopper_log_%4d_%02d_%02d.log", log_file_path, timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday);
	//printf("log file name: %s\n", log_file_name);
	log_file_ptr = fopen(log_file_name, "a+");
	cout << "fopen " << log_file_ptr << endl;
	if (log_file_ptr == 0)
	{
		sprintf(log_file_name, "%shopper_log_%4d_%02d_%02d.log", log_file_path, timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday);
		log_file_ptr = fopen(log_file_name, "a+");
		cout << "fopen " << log_file_ptr << endl;
	}
	if (log_file_ptr == 0)
		cout << "unable to open Log file" << endl;
	cout << "Log file name " << log_file_name << endl;
	strcpy(log_str, "init resources object");
	log_add_str(log_str);
	for(int i1 = 0; i1 < 8; i1++)
		for(int i2 = 0; i2 < 6; i2++)
		Ser_nr[i1][i2] = 0;
	serial_is_opened = false;

	return;
}
hopper_device::~hopper_device()
{
	//int ret_val = 0;
	//int err_code = 0;
	//char log_str[63];
	port_close();
	close_d2xx();
	return;
}
int hopper_device::log_add_str(char * log_str)
{
	//int ret_val = 0;
	if (log_file_ptr != NULL)
	{
		char formatted_time[63];
		time_t rawtime;
		struct tm * timeinfo;
		time ( &rawtime );
		timeinfo = localtime ( &rawtime );
		log_file_year_day_prev = log_file_year_day_pres;
		//log_file_year_day_pres = timeinfo->tm_yday;
		log_file_year_day_pres = timeinfo->tm_mday;
		if (log_file_year_day_prev != log_file_year_day_pres)
		{
			//printf("next log file\n");
			sprintf(log_file_name, "%shopper_log_%4d_%2d_%2d.log", log_file_path, timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday);
			//printf("new log file name: %s\n", log_file_name);
			fclose(log_file_ptr);
			log_file_ptr = fopen(log_file_name, "a+");
		}
		//strftime (formatted_time, 63, "%Y.%m.%d %X",timeinfo);
		strftime (formatted_time, 63, "%X",timeinfo);
		fprintf(log_file_ptr, "%s : %s\n", formatted_time, log_str);
		fflush(log_file_ptr);
	}
	return 0;
}

int hopper_device::open_d2xx_dll(void)
{
	int ret_val = 0;
	int func_counter = 0;
	int load_func_err = 0;
	char log_str[63];
	h_d2xx_dll = LoadLibrary("../../Hopper_EV2000_Boost_DLL/Cross_GCC_Boost_Debug/ftd2xx.dll");
	if (!(h_d2xx_dll > (void*)HINSTANCE_ERROR))
		h_d2xx_dll = LoadLibrary("ftd2xx.dll");
	if (!(h_d2xx_dll > (void*)HINSTANCE_ERROR))
	{
		sprintf(log_str, " ser_port::open_d2xx unable LoadLibrary(""ftd2xx.dll"") error");
		printf("%s\n", log_str);
		log_add_str(log_str);
		ret_val = -1;
		d2xx_dll_is_loaded = 0;
	}
	else
	{
		printf("LoadLibrary(""ftd2xx.dll"") OK\n");
		d2xx_dll_is_loaded = 1;
	}
	if(h_d2xx_dll > (void*)HINSTANCE_ERROR)
	{
		func_counter++;
		if (! (FT_Open = (t_FT_Open)GetProcAddress(h_d2xx_dll, "FT_Open")))
		{
			printf("Error locating FT_Open function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_OpenEx = (t_FT_OpenEx)GetProcAddress(h_d2xx_dll, "FT_OpenEx")))
		{
			printf("Error locating FT_OpenEx function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_Close = (t_FT_Close)GetProcAddress(h_d2xx_dll, "FT_Close")))
		{
			printf("Error locating FT_Close function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_Purge = (t_FT_Purge)GetProcAddress(h_d2xx_dll, "FT_Purge")))
		{
			printf("Error locating FT_Purge function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_CreateDeviceInfoList = (t_FT_CreateDeviceInfoList)GetProcAddress(h_d2xx_dll, "FT_CreateDeviceInfoList")))
		{
			printf("Error locating FT_CreateDeviceInfoList function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_GetDriverVersion = (t_FT_GetDriverVersion)GetProcAddress(h_d2xx_dll, "FT_GetDriverVersion")))
		{
			printf("Error locating FT_GetDriverVersion function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_GetDeviceInfoList = (t_FT_GetDeviceInfoList)GetProcAddress(h_d2xx_dll, "FT_GetDeviceInfoList")))
		{
			printf("Error locating FT_GetDeviceInfoList function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_GetComPortNumber = (t_FT_GetComPortNumber)GetProcAddress(h_d2xx_dll, "FT_GetComPortNumber")))
		{
			printf("Error locating FT_GetComPortNumber function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_SetBaudRate = (t_FT_SetBaudRate)GetProcAddress(h_d2xx_dll, "FT_SetBaudRate")))
		{
			printf("Error locating FT_SetBaudRate function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_SetTimeouts = (t_FT_SetTimeouts)GetProcAddress(h_d2xx_dll, "FT_SetTimeouts")))
		{
			printf("Error locating FT_SetTimeouts function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_SetDataCharacteristics = (t_FT_SetDataCharacteristics)GetProcAddress(h_d2xx_dll, "FT_SetDataCharacteristics")))
		{
			printf("Error locating FT_SetDataCharacteristics function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_SetFlowControl = (t_FT_SetFlowControl)GetProcAddress(h_d2xx_dll, "FT_SetFlowControl")))
		{
			printf("Error locating FT_SetFlowControl function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_Read = (t_FT_Read)GetProcAddress(h_d2xx_dll, "FT_Read")))
		{
			printf("Error locating FT_Read function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_Write = (t_FT_Write)GetProcAddress(h_d2xx_dll, "FT_Write")))
		{
			printf("Error locating FT_Write function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_GetDriverVersion = (t_FT_GetDriverVersion)GetProcAddress(h_d2xx_dll, "FT_GetDriverVersion")))
		{
			printf("Error locating FT_GetDriverVersion function \n");
			load_func_err |= 0x01 << func_counter;
		}
		func_counter++;
		if (! (FT_GetLibraryVersion = (t_FT_GetLibraryVersion)GetProcAddress(h_d2xx_dll, "FT_GetLibraryVersion")))
		{
			printf("Error locating FT_GetLibraryVersion function \n");
			load_func_err |= 0x01 << func_counter;
		}

		if (! (FT_W32_GetLastError = (t_FT_W32_GetLastError)GetProcAddress(h_d2xx_dll, "FT_W32_GetLastError")))
		{
			printf("Error locating FT_W32_GetLastError function \n");
			load_func_err |= 0x01 << func_counter;
		}
		if (! (FT_CyclePort = (t_FT_CyclePort)GetProcAddress(h_d2xx_dll, "FT_CyclePort")))
		{
			printf("Error locating FT_CyclePort function \n");
			load_func_err |= 0x01 << func_counter;
		}
		if (! (FT_Rescan = (t_FT_Rescan)GetProcAddress(h_d2xx_dll, "FT_Rescan")))
		{
			printf("Error locating FT_Rescan function \n");
			load_func_err |= 0x01 << func_counter;
		}
		if (! (FT_ResetDevice = (t_FT_ResetDevice)GetProcAddress(h_d2xx_dll, "FT_ResetDevice")))
		{
			printf("Error locating FT_ResetDevice function \n");
			load_func_err |= 0x01 << func_counter;
		}
		if (! (FT_ResetPort = (t_FT_ResetPort)GetProcAddress(h_d2xx_dll, "FT_ResetPort")))
		{
			printf("Error locating FT_ResetPort function \n");
			load_func_err |= 0x01 << func_counter;
		}

	}
	ret_val |= load_func_err;
	return ret_val;
}

int hopper_device::get_ser_No(char * vpPort_name)
{
	int ret_val = 0;
	int ser_port_no = -1;
	//int ser_port_name_upercase_pos = 0;
	char * ser_port_name_upercase_pos = 0;
	char ser_port_name_uppercase[15];
	int i1 = 0;
	char log_str[63];
	for (i1 = 0; i1 < strlen(vpPort_name); i1++)
	{
	    ser_port_name_uppercase[i1] = toupper(vpPort_name[i1]);
	}
	ser_port_name_uppercase[i1++] = 0;
	ser_port_name_upercase_pos = strstr(ser_port_name_uppercase, "COM");
	if (ser_port_name_upercase_pos < 0)
	{
		sprintf(log_str, " hopper_device::get_ser_No incorrect serial name error");
		printf("%s\n", log_str);
		log_add_str(log_str);
		//ret_val = 1;
		return ret_val;
	}
	else
	{
		printf("ser_no_str %s.\n", ser_port_name_upercase_pos + 3);
	}
	sscanf(ser_port_name_upercase_pos + 3, "%d", &ser_port_no);
	printf("ser_no %d\n", ser_port_no);
	ret_val = ser_port_no;
	return ret_val;
}
int hopper_device::open_d2xx(void)
{
	//printf("open_d2xx\n");
	int ret_val = 0;
	int ret_res = 0;
	int i1 = 0;
	ret_res = open_d2xx_dll();
	int load_func_err = 0;
	int func_counter = 0;
	FT_HANDLE ft_handle_local;
	FT_HANDLE ft_handle_local_arr[3];
	//p_FT_DEVICE_LIST_INFO_NODE = (FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);
	FT_DEVICE_LIST_INFO_NODE p_FT_DEVICE_LIST_INFO_NODE[15];
	DWORD numDevs;
	int ft_sel_index = -1;
	//FT_DEVICE_LIST_INFO_NODE *p_FT_DEVICE_LIST_INFO_NODE;
	//int ser_port_no = -1;
	long ft_port_no = 0;
	char log_str[63];
	//printf("uppercase\n");
	//printf("ser_name %s.\n", ser_port_name);
	//ser_port_no = get_ser_No(ser_port_name);
	ft_status = FT_CreateDeviceInfoList(&numDevs);
	int local_numDevs = numDevs;
	if (ft_status == FT_OK)
	{
		printf("number of devices %d\n", numDevs);
	}
	else
	{
		sprintf(log_str, " hopper_device::open_d2xx FT_CreateDeviceInfoList error : %d", ft_status);
		printf("%s\n", log_str);
		log_add_str(log_str);
		ret_val = 2;
		return ret_val;
	}
	ft_status = FT_GetDeviceInfoList(p_FT_DEVICE_LIST_INFO_NODE, &numDevs);
	//printf(" search=%d\n", ser_port_no);
	printf(" search=%d\n", ser_port_No);
	for (int i = 0; i < local_numDevs; i++)
	{
		printf("Dev %d of %d:\n", i, numDevs);
		printf(" Flags=0x%x\n",p_FT_DEVICE_LIST_INFO_NODE[i].Flags);
		printf(" Type=0x%x\n",p_FT_DEVICE_LIST_INFO_NODE[i].Type);
		printf(" ID=0x%x\n",p_FT_DEVICE_LIST_INFO_NODE[i].ID);
		printf(" LocId=0x%x\n",p_FT_DEVICE_LIST_INFO_NODE[i].LocId);
		printf(" SerialNumber=%s\n",p_FT_DEVICE_LIST_INFO_NODE[i].SerialNumber);
		printf(" Description=%s\n",p_FT_DEVICE_LIST_INFO_NODE[i].Description);
		printf(" ftHandle=0x%x\n",p_FT_DEVICE_LIST_INFO_NODE[i].ftHandle);
		//ft_status = FT_Open(i, &ft_handle_local);
		int try_no = 0;
		int try_result = 0;
		do
		{
			try_no++;
			switch (try_no)
			{
				case 1:
					ft_status = FT_Open(i, &ft_handle_local);
					sprintf(log_str, " hopper_device::open_d2xx[%d] scan try No %d ft_status = %d\n", i, try_no, ft_status);
					printf("%s\n", log_str);
					log_add_str(log_str);
					if (ft_status == FT_OK)
					{
						try_result = 0;
					}
					else
					{
						FT_Close(ft_handle_local);
						try_result = 1;
					}
					break;
				case 2:
					ft_status = FT_Open(i, &ft_handle_local);
					sprintf(log_str, " hopper_device::open_d2xx[%d] scan try No %d ft_status = %d\n", i, try_no, ft_status);
					printf("%s\n", log_str);
					log_add_str(log_str);
					ft_status = FT_CyclePort(ft_handle_local);
					sprintf(log_str, " hopper_device::FT_CyclePort[%d] scan try No %d ft_status = %d\n", i, try_no, ft_status);
					printf("%s\n", log_str);
					log_add_str(log_str);
					if (ft_status == FT_OK)
					{
						try_result = 0;
					}
					else
					{
						FT_Close(ft_handle_local);
						try_result = 2;
					}
					break;
				default:
					break;
			}
		}
		while(try_no < 2 && try_result != 0);
		//printf(" search=%d\n", ser_port_no);
		printf(" search=%d\n", ser_port_No);
		printf("  FT_Open(%d, %d):%d\n", i, ft_handle_local, ft_status);
		if(ft_status == FT_OK)
		{
			ft_status = FT_GetComPortNumber(ft_handle_local, &ft_port_no);
			if (ft_status == FT_OK)
			{
				//printf(" port=%d search=%d\n", ft_port_no, ser_port_no);
				printf(" port=%d search=%d\n", ft_port_no, ser_port_No);
				//if (ser_port_no == ft_port_no)
				if (ser_port_No == ft_port_no)
				{
					printf(" * it is here");
					ft_handle = ft_handle_local;
					ft_sel_index = i;
					ft_LocId = p_FT_DEVICE_LIST_INFO_NODE[i].LocId;
					printf(" index %d loc %d\n", ft_sel_index, ft_LocId);
				}
			}
			else
			{
				sprintf(log_str, " hopper_device::open_d2xx Unable FT_GetComPortNumber, error %d\n", ft_status);
				printf("%s\n", log_str);
				log_add_str(log_str);
				ret_val = 3;
				//return ret_val;
			}
			ft_status = FT_Close(ft_handle_local);
			if (ft_status == FT_OK){}
			else
			{
				sprintf(log_str, " hopper_device::open_d2xx FT_Close error : %d", ft_status);
				printf("%s\n", log_str);
				log_add_str(log_str);
				ret_val = 4;
				//return ret_val;
			}
		}else
		{
			sprintf(log_str, " ::open_d2xx Unable to open device %d ft_status = %d\n", i, ft_status);
			printf("%s\n", log_str);
			log_add_str(log_str);
			ret_res = FT_W32_GetLastError(ft_handle);
			sprintf(log_str, " ::open_d2xx FT_W32_GetLastError %d", ret_res);
			printf("%s\n", log_str);
			log_add_str(log_str);
			ret_val = 5;
			//return ret_val;
		}
	}
	sprintf(log_str, " ------- ::open_d2xx scan finished, result %d", ret_val);
	printf("%s\n", log_str);
	log_add_str(log_str);
	if (ft_sel_index >= 0)
	{
		ret_val = 0;
		sprintf(log_str, "Open index %d\n", ft_sel_index);
		printf("%s\n", log_str);
		log_add_str(log_str);
		//int try_no = 0;
		//int try_result = 1;
		ft_status = FT_Open(ft_sel_index, &ft_handle);
		/*
		while(try_no < 3 && try_result != 0)
		{
			ft_status = FT_Open(ft_sel_index, &ft_handle);
			sprintf(log_str, " ser_port::open_d2xx try No %d ft_status = %d\n", try_no, ft_status);
			printf("%s\n", log_str);
			log_add_str(log_str);
			if (ft_status == FT_OK)
			{
				try_result = 0;
			}
			else
			{
				FT_Close(ft_handle_local);
				switch (try_no)
				{
				default:
					FT_CyclePort(ft_handle);
					break;
				}
			}
			try_no++;
		}
		*/
		d2xx_opened = 1;
		if (ft_status == FT_OK)
		{
			//printf(" opened\n");
		}
		else
		{
			sprintf(log_str, " ::open_d2xx FT_Open error : %d", ft_status);
			printf("%s\n", log_str);
			log_add_str(log_str);
			ret_val = 6;
			return ret_val;
		}
		if (ft_status == FT_OK)
		{
			sprintf(log_str, " ::open_d2xx set parameters baud %d", baud);
			printf("%s\n", log_str);
			log_add_str(log_str);
			ft_status |= FT_SetBaudRate(ft_handle, baud);
			ft_status |= FT_SetDataCharacteristics(ft_handle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE);
			ft_status |= FT_SetTimeouts(ft_handle, 200, 200);
			ft_status |= FT_SetFlowControl(ft_handle, FT_FLOW_NONE, 0x11, 0x13);
			if (ft_status == FT_OK)
			{
				printf(" set parameters OK\n");
				log_add_str(const_cast<char *>("FT set parameters OK"));
			}
			else
			{
				sprintf(log_str, " ::open_d2xx set parameters error : %d", ft_status);
				printf("%s\n", log_str);
				log_add_str(log_str);
			}
			ft_handle_opened = 1;
			if ( ft_handle_opened == 1 && read_buff_after_writing)
			{
				char buf_str[63];
				int ret_len = 0;
				Sleep(1000);
				read_buf(buf_str, &ret_len, 63);
			}

		}
		if (ft_status != FT_OK)
		{
			ret_res = FT_W32_GetLastError(ft_handle);
			sprintf(log_str, " ::open_d2xx error %n", ret_res);
			printf("%s\n", log_str);
			log_add_str(log_str);
		}

	}
	else
	{
		sprintf(log_str, " ::open_d2xx ft_sel_index < 0 error");
		printf("%s\n", log_str);
		log_add_str(log_str);
		ret_val = 7;
		ft_status = FT_Close(ft_handle);
		d2xx_opened = 0;
		return ret_val;

	}
	return ret_val;
}

int hopper_device::close_d2xx(void)
{
	char log_str[31];
	int ret_val = 0;
	ft_status = FT_Close(ft_handle);
	sprintf(log_str, " ::close_d2xx %d", ft_status);
	printf("%s\n", log_str);
	log_add_str(log_str);
	ret_val = ft_status;
	return ret_val;
}
int hopper_device::open_ser()
{
	int ret_val = 0;
	int res_var = 0;
	int err_code = 0;
	serial_is_opened = 0;
	char log_str[63];
	printf(" open port %s\n", ser_port_name);
	//strcpy(ser_port_name, "//./COM17");
	hPort=CreateFile(
		ser_port_name, GENERIC_WRITE+GENERIC_READ, 0, NULL,
		OPEN_EXISTING, FILE_FLAG_OVERLAPPED*0, 0 );
	if (hPort == INVALID_HANDLE_VALUE)
	{
		ret_val = 1;
		err_code = GetLastError();
		sprintf(log_str, " ::open_ser CreateFile(%s) error GetLastError: %d", ser_port_name, err_code);
		log_add_str(log_str);
	}
	else
	{
		GetCommState(hPort, &dcb_prev);
		dcb_curr = dcb_prev;
		dcb_curr.DCBlength = sizeof(DCB);
		dcb_curr.BaudRate = baud;
		dcb_curr.fBinary = TRUE;
		dcb_curr.fOutxCtsFlow = FALSE;
		dcb_curr.fOutxDsrFlow = FALSE;
		dcb_curr.fDtrControl = DTR_CONTROL_DISABLE;
		dcb_curr.fTXContinueOnXoff = TRUE;
		dcb_curr.fOutX = FALSE;
		dcb_curr.fInX = FALSE;
		dcb_curr.fDsrSensitivity = FALSE;
		dcb_curr.fNull = FALSE;
		dcb_curr.fRtsControl = RTS_CONTROL_DISABLE;
		dcb_curr.fAbortOnError = FALSE;
		dcb_curr.ByteSize = 8;
		dcb_curr.Parity = NOPARITY;
		dcb_curr.fParity = FALSE;
		dcb_curr.StopBits = ONESTOPBIT;
		dcb_curr.fNull = FALSE;
		dcb_curr.fAbortOnError = FALSE;

		if (SetCommState(hPort, &dcb_curr) == 0)
		{
			ret_val = 2;
			err_code = GetLastError();
			sprintf(log_str, " ser_port::open SetCommState error GetLastError: %d", err_code);
			log_add_str(log_str);
			CloseHandle(hPort);
		}
		else
		{
			GetCommTimeouts( hPort, &CommTimeOuts_prev);
			CommTimeOuts_curr = CommTimeOuts_prev;
			CommTimeOuts_curr.WriteTotalTimeoutMultiplier=2;
			CommTimeOuts_curr.WriteTotalTimeoutConstant=500;
			CommTimeOuts_curr.ReadIntervalTimeout=40;
			CommTimeOuts_curr.ReadTotalTimeoutMultiplier=1;
			CommTimeOuts_curr.ReadTotalTimeoutConstant=500;
			SetCommTimeouts( hPort, &CommTimeOuts_curr);
			ret_val = 0;
			/*
			CommTimeOuts.ReadIntervalTimeout= 10;
			CommTimeOuts.ReadTotalTimeoutMultiplier = 1;
			// значений этих тайм – аутов вполне хватает для уверенного приема
			// даже на скорости 110 бод
			CommTimeOuts.ReadTotalTimeoutConstant = 100;
			// используется в данном случае как время ожидания посылки
			CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
			CommTimeOuts.WriteTotalTimeoutConstant = 0;
			SetCommTimeouts(handle, &CommTimeOuts); */
			serial_is_opened = 1;
		}
	}
	if (read_buff_after_writing)
	{
		char buf_str[63];
		int ret_len = 0;
		Sleep(1000);
		read_buf(buf_str, &ret_len, 63);
	}
	return ret_val;
}
int hopper_device::port_close(void)
{
	int ret_val = 0;
	int err_code = 0;
	char log_str[64];
	if (serial_is_opened == 1)
	{
		if (SetCommState(hPort, &dcb_prev) == 0)
		{
			ret_val = 2;
			err_code = GetLastError();
			sprintf(log_str, " ser_port::close SetCommState error GetLastError: %d", err_code);
			log_add_str(log_str);
		}
		if (SetCommTimeouts(hPort, &CommTimeOuts_prev) == 0)
		{
			ret_val = 3;
			err_code = GetLastError();
			sprintf(log_str, " ser_port::close SetCommTimeouts error GetLastError: %d", err_code);
			log_add_str(log_str);
		}
		if (CloseHandle(hPort) == 0)
		{
			ret_val = 4;
			err_code = GetLastError();
			sprintf(log_str, " ser_port::close CloseHandle error GetLastError: %d", err_code);
			log_add_str(log_str);
		}
		serial_is_opened = 0;
	}
	return ret_val;

}

int hopper_device::device_write(char lpBuffer[], int dwBytesToWrite, int * lpdwBytesWritten)
{
	int err_code = 0;
	int res_var = 0;
	char log_str[63];
	int ret_val = 0;
	if (d2xx_opened == 1)
	{
		ft_status = FT_Write(ft_handle, lpBuffer, dwBytesToWrite, (DWORD*)lpdwBytesWritten);
		if (ft_status != FT_OK)
		{
			ret_val = -1;
			err_code = FT_W32_GetLastError(ft_handle);
			sprintf(log_str, " hopper_device::cctalk_write_n_bytes FT_Write error ft_status %d GetLastError: %d", ft_status, err_code);
			log_add_str(log_str);
		}
		else
		{
			/*printf(" + device write dwBytesToWrite %d dwBytesWritten %d\n", dwBytesToWrite, * lpdwBytesWritten);
			for (int i1 = 0; i1 < (*lpdwBytesWritten); i1++)
			{
				printf(" [%d]%2X ", i1, lpBuffer[i1]);
			};
			printf("\n");*/
		}
	}
	else if (serial_is_opened == 1)
	{
		res_var = WriteFile(hPort, lpBuffer, dwBytesToWrite + 1, (DWORD*)lpdwBytesWritten, NULL);
		if ( !res_var )
		{
			ret_val = -1;
			err_code = GetLastError();
			sprintf(log_str, " hopper_device::cctalk_write_n_bytes WriteFile error GetLastError: %d", err_code);
			log_add_str(log_str);
			//cout << endl << log_str << endl;
		}
	}
	else
	{
		sprintf(log_str, " hopper_device::cctalk_write_n_bytes error device not opened");
		printf("%s\n", log_str);
		log_add_str(log_str);
	}
	return ret_val;
}
int hopper_device::device_read (char lpBuffer[], int dwBytesToRead , int * lpdwBytesReturned)
{
	int ret_val = 0;
	int err_code = 0;
	char log_str[63];
	if (d2xx_opened == 1)
	{
		ft_status = FT_Read(ft_handle, lpBuffer, dwBytesToRead, (DWORD*)lpdwBytesReturned);
		//if ( !ReadFile(hPort, buf, size, (DWORD*)n_recv, NULL))
		if (ft_status != FT_OK)
		{
			ret_val = -1;
			err_code = FT_W32_GetLastError(ft_handle);
			//err_code = GetLastError();
			sprintf(log_str, " ser_port::read_buf ReadFile error FT_W32_GetLastError: %d", err_code);
			log_add_str(log_str);
		}
		else
		{
			/*printf(" + device read dwBytesToRead %d lpdwBytesReturned %d\n", dwBytesToRead, * lpdwBytesReturned);
			for (int i1 = 0; i1 < (*lpdwBytesReturned); i1++)
			{
				printf(" [%d]%2X ", i1, lpBuffer[i1]);
			};
			printf("\n");*/
			ret_val = * lpdwBytesReturned;
		}

	}
	else
	{
		if (serial_is_opened == 1)
		{
			if ( !ReadFile(hPort, lpBuffer, dwBytesToRead, (DWORD*)lpdwBytesReturned, NULL))
			{
				ret_val = -1;
				err_code = GetLastError();
				sprintf(log_str, " ser_port::read_buf ReadFile error GetLastError: %d", err_code);
				log_add_str(log_str);
			}
			else
				ret_val = * lpdwBytesReturned;
		}
		else
		{
			ret_val = -1;
		}
	}
	return ret_val;
}

int hopper_device::read_buf(char * buf, int * n_recv, int size)
{
	//int ret_val;
	//int err_code = 0;
	//char log_str[63];
	return device_read(buf, size, n_recv);
}
int hopper_device::purge_buf(void)
{
	int ret_val = 0;
	int err_code = 0;
	char log_str[63];
	if (serial_is_opened == 1)
	{
		if(PurgeComm(hPort, PURGE_TXCLEAR | PURGE_RXCLEAR) == 0)
		{
			err_code = GetLastError();
			sprintf(log_str, " ::purge_buf PurgeComm GetLastError: %d", err_code);
			printf("%s\n", log_str);
			log_add_str(log_str);
			ret_val = err_code;
		}
	}
	if (d2xx_opened == 1)
	{
		ft_status = FT_Purge(ft_handle, FT_PURGE_RX | FT_PURGE_TX);
		if(ft_status != FT_OK)
		{
			err_code = FT_W32_GetLastError(ft_handle);
			sprintf(log_str, " ::purge_buf PurgeComm error ft_status: %d FT_W32_GetLastError %d", ft_status, err_code);
			printf("%s\n", log_str);
			log_add_str(log_str);
			ret_val = ft_status;
		}
	}
	return ret_val;
}
//input - n bytes of data to transmit without checksum byte
// function evaluates checksum byte and return it
char hopper_device::cctalk_checksum(char * vp_inp_arr, char n_inp)
{
	char buf_byte;
	char i1;
	buf_byte = 0;
	for( i1 = 0; i1 < n_inp; i1++)
	{
		buf_byte += vp_inp_arr[i1];
	}
	buf_byte = (char)(256-buf_byte);
	return buf_byte;
}
//function sends n bytes of vp_byte_arr to cctalk, receives reply and returns it in vp_byte_arr_out
int hopper_device::cctalk_write_n_bytes(char * vp_byte_arr, char * vp_byte_arr_out, char n)
{
	//int Num_Tx = 0;
	int Num_Rx = 0;;
	std::stringstream Buf_str;
	//byte Buf_byte;
	int i1;
	int ret_val = 0;
	int res_var = 0;
	DWORD n_send = 0;
	DWORD n_recv = 0;
	int fv_result = 0;
	int err_code = 0;
	char log_str[63];
	try
	{
		vp_byte_arr[n] = cctalk_checksum(vp_byte_arr, n);
		//cout << (unsigned short)(vp_byte_arr[n]);
		//cout << "WriteFile:" << endl;
		for (i1 = 0; i1 < n + 1; i1++)
		{
			//printf("%02X ", (unsigned char)vp_byte_arr[i1]);
		}
		res_var = device_write(vp_byte_arr, n + 1, (int*)&n_send);
		//cout << "Ready " << n_send << " bytes " << endl;
		Sleep(100);
		//Console.WriteLine("Sleep -> BytesToRead {0}", Port_handle.BytesToRead);
		try
		{
			//cout << "ReadFile n=" << (int)n << "...";
			res_var = device_read(vp_byte_arr_out, n + 1, (int*)&n_recv);
			//cout << "Ready " << n_recv << " bytes " << endl;
			Num_Rx = n_recv;
			Buf_str << "";
			//for(i1 = 0; i1 <= n + 1; i1++) Buf_str = Buf_str + ' ' + vp_byte_arr_out[i1].ToString("X");
			//Console.WriteLine("Received Tx {0} is {1}", Num_Rx, Buf_str);
			res_var = device_read(vp_byte_arr_out, 31, (int*)&n_recv);
			//ReadFile(hPort, vp_byte_arr_out, 31, &n_recv, NULL);
			Num_Rx = n_recv;//Num_Rx);
			//Console.WriteLine("Readed Ans {0}", Num_Rx);
		}
		catch (exception & e)
		{
			fv_result = 5;
			cout << "Read port exception " << e.what() << endl;
			//printf("Read port exception %d", e);
			return fv_result;
		}
		if (Num_Rx > 31) Num_Rx = 31;
		//Buf_str << "Num_Rx:" << Num_Rx;
		//cout << Buf_str << endl;
		//cout << "Num_Rx:" << Num_Rx << endl;
		//Buf_str << "";
		//Console.WriteLine("Received {0} is {1}", Num_Rx, Buf_str);
		if (Num_Rx != 0)
		{
			if (Num_Rx < 255)
			{
				//cout << "cctalk_checksum...";
				if (vp_byte_arr_out[Num_Rx - 1] == cctalk_checksum(vp_byte_arr_out, Num_Rx - 1))
				{
					//cout << "OK" << endl;
					//Console.WriteLine("Received checksum OK");
					fv_result = 0;
				}
				else
				{
					printf("Received checksum failed\n");
					fv_result = 1;
				}
			}
			else
			{
				printf("Received %d bytes, over 255\n", Num_Rx);
				fv_result = 4;
			}
		}
		else
		{
			printf("Received Empty\n");
			fv_result = 2;
		}
	}
		catch (exception & e)
		{
			cout << "Port write exception " << e.what() << endl;
			fv_result = 3;
		}
	return fv_result;
}
int hopper_device::cctalk_reset_device(char addr)
{
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0x01;
	//Console.WriteLine("* Reset addr {0}", addr);
	//cout << "cctalk_write_n_bytes...";
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	//cout << fv_result << endl;
	return fv_result;
}
int hopper_device::cctalk_enable_hopper(char addr)
{
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x01;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA4;
	Buf_Tx[4] = 0xA5;
	return cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 5);
}
int hopper_device::cctalk_disable_hopper(char addr)
{
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x01;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA4;
	Buf_Tx[4] = 0x00;
	return cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 5);
}
int hopper_device::cctalk_request_serial_nr(char addr, char * vp_byte_arr)
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xF2;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	Ser_nr[0][static_cast<int>(addr)] = Buf_Rx[4];
	Ser_nr[1][static_cast<int>(addr)] = Buf_Rx[5];
	Ser_nr[2][static_cast<int>(addr)] = Buf_Rx[6];
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}

int hopper_device::cctalk_send_simple_pool(char addr)
{
	//Console.WriteLine("Simple poll addr {0}", addr);
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xFE;
	Buf_Tx[4] = 0xFE;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	//if f_result = 0 then Hoppers_state[addr] = 1;      // set state of hopper with address i1 to present
	return fv_result;
}
int hopper_device::cctalk_address_pool(char * addr)
{
	int ret_val;
	int res_var = 0;
	char log_str[63];
	//int Num_Tx;
	int Num_Rx;
	int fv_result;
	DWORD n_send;
	DWORD n_recv;
	int err_code = 0;
	Buf_Tx[0] = 0x00;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xFD;
	Buf_Tx[4] = 0x02;
	try
	{
		res_var = device_write(Buf_Tx, 5, (int*)&n_send);
		//if ( !WriteFile(hPort, Buf_Tx, 5, &n_send, NULL))
		if (res_var != 0)
		{
			ret_val = -1;
			//err_code = GetLastError();
			//sprintf(log_str, " hopper_device::cctalk_Address_Pool WriteFile error GetLastError: %d", err_code);
			sprintf(log_str, " hopper_device::cctalk_Address_Pool write error see before");
			//log_add_str(log_str);
		}
		//Console.WriteLine("Transmitted {0}", Num_Tx);
		Sleep(10);
		//Num_Rx = Port_handle.Read(Buf_Rx, 0, 31);
		res_var = device_read(Buf_Rx, 31, (int*)&n_recv);
		//if ( !ReadFile(hPort, Buf_Rx, 31, &n_recv, NULL))
		if (res_var != 0)
		{
			ret_val = -1;
			//err_code = GetLastError();
			//sprintf(log_str, " hopper_device::cctalk_Address_Pool ReadFile error GetLastError: %d", err_code);
			sprintf(log_str, " hopper_device::cctalk_Address_Pool read error see before");
			log_add_str(log_str);
		}
		Num_Rx = n_recv;
		//Console.WriteLine("Received {0} addr {1}", Num_Rx, Buf_Rx[5]);
		if(Num_Rx == 6)
		{
			*addr = Buf_Rx[5];
			fv_result = 0;
		}
		else
		{
			*addr = 0;
			fv_result = 1;
		}
	}
	catch (exception & e)
	{
		//printf("Address poll exception %d\n", e);
		cout << "Address poll exception " << e.what() << endl;
		*addr = 0;
		fv_result = 2;
	}
	return fv_result;
}
int hopper_device::cctalk_request_comms_revision(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result = 0;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0x04;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_comms_status_variables(char addr, char vp_byte_arr[])
{
	//byte[] Buf_Tx;
	//byte[] Buf_Rx;
	char i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0x02;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	if (Buf_Rx[1] != 0)
	  for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
		vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_clear_comms_variables(char addr)
{
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0x03;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	return fv_result;
}
int hopper_device::cctalk_request_manufacturer_id(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xF6;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_equipment_category_id(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xF5;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_product_code(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xF4;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_software_revision(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xF1;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_data_storage_availability(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xD8;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_build_code(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xC0;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_address_mode(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA9;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_enter_PIN_number(char addr, char vp_PIN_number[])
{
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x04;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xDA;
	Buf_Tx[4] = vp_PIN_number[0];
	Buf_Tx[5] = vp_PIN_number[1];
	Buf_Tx[6] = vp_PIN_number[2];
	Buf_Tx[7] = vp_PIN_number[3];
	return cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 8);
}
int hopper_device::cctalk_enter_new_PIN_number(char addr, char vp_PIN_number[])
{
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x04;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xDB;
	Buf_Tx[4] = vp_PIN_number[0];
	Buf_Tx[5] = vp_PIN_number[1];
	Buf_Tx[6] = vp_PIN_number[2];
	Buf_Tx[7] = vp_PIN_number[3];
	return cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 8);
}
int hopper_device::cctalk_modify_variable_settings(char addr, char vp_variable_settings[])
{
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x04;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA5;
	Buf_Tx[4] = vp_variable_settings[0];
	Buf_Tx[5] = vp_variable_settings[1];
	Buf_Tx[6] = vp_variable_settings[2];
	Buf_Tx[7] = vp_variable_settings[3];
	return cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 8);
}
int hopper_device::cctalk_request_variable_settings(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xF7;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_test_hopper(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	char log_str[63];
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA3;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	sprintf(log_str, " hopper_device::cctalk_test_hopper : %2X %2X %2X %2X %2X %2X", \
			Buf_Rx[0], Buf_Rx[1], Buf_Rx[2], Buf_Rx[3], Buf_Rx[4], Buf_Rx[5] );
	printf("%s\n", log_str);
	log_add_str(log_str);
	return fv_result;
}
int hopper_device::cctalk_hopper_status(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	char log_str[63];
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA6;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	sprintf(log_str, " hopper_device::cctalk_hopper_status : %2X %2X %2X %2X %2X %2X %2X %2X", \
			Buf_Rx[0], Buf_Rx[1], Buf_Rx[2], Buf_Rx[3], Buf_Rx[4], Buf_Rx[5], Buf_Rx[6], Buf_Rx[7] );
	printf("%s\n", log_str);
	log_add_str(log_str);
	return fv_result;
}
int hopper_device::cctalk_emergency_stop(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xAC;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_empty_hopper(char addr, char vp_byte_arr[], int coins_to_put)
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x04;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0x19;
	Buf_Tx[4] = Ser_nr[0][static_cast<int>(addr)];
	Buf_Tx[5] = Ser_nr[1][static_cast<int>(addr)];
	Buf_Tx[6] = Ser_nr[2][static_cast<int>(addr)];
	Buf_Tx[7] = (byte)coins_to_put;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 8);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
// Request Payout high/low status
//  bits have the following meaning:
//  0: Low Level status (1 = low level)
//  1: High Level status (1 = high level)
//  4: Low Level sensor is fitted
//  5: High Level sensor is fitted
int hopper_device::cctalk_request_payout_hi_lo_status(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xD9;
	fv_result = cctalk_write_n_bytes( Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
/*int hopper_device::cctalk_disable_hopper(char addr)
{res_var
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x01;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA4;
	Buf_Tx[4] = 0x00;
	return cctalk_write_n_bytes(Buf_Tx, Buf_Rx, 5);
}*/
int hopper_device::cctalk_pump_RNG(char addr, char vp_RNG[])
{
	int i1;
	//int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA1;
	for(i1 = 0; i1 <= 7; i1++ )
	  Buf_Tx[i1 + 4] = vp_RNG[i1];
	return cctalk_write_n_bytes(Buf_Tx, Buf_Rx, 12);
}
int hopper_device::cctalk_request_cipher_key(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA0;
	fv_result = cctalk_write_n_bytes(Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_dispense_coins(char addr, char vp_byte_arr[], int coins_to_put)
{
	int i1;
	int fv_result;
	char log_str[63];
	sprintf(log_str, " hopper_device::cctalk_dispense_coins : %d", coins_to_put);
	printf("%s\n", log_str);
	log_add_str(log_str);
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x04;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA7;
	Buf_Tx[4] = Ser_nr[0][static_cast<int>(addr)];
	Buf_Tx[5] = Ser_nr[1][static_cast<int>(addr)];
	Buf_Tx[6] = Ser_nr[2][static_cast<int>(addr)];
	Buf_Tx[7] = (byte)coins_to_put;
	fv_result = cctalk_write_n_bytes(Buf_Tx, Buf_Rx, 8);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_request_hopper_dispense_count(char addr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x00;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA8;
	fv_result = cctalk_write_n_bytes(Buf_Tx, Buf_Rx, 4);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_read_data_block(char addr, char data_block_nr, char vp_byte_arr[])
{
	int i1;
	int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = 0x01;
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xD7;
	Buf_Tx[4] = data_block_nr;
	fv_result = cctalk_write_n_bytes(Buf_Tx, Buf_Rx, 5);
	vp_byte_arr[0] = Buf_Rx[1];
	for(i1 = 0; i1 <= Buf_Rx[1] - 1; i1++)
	  vp_byte_arr[i1 + 1] = Buf_Rx[4 + i1];
	vp_byte_arr[Buf_Rx[1] + 1] = 0;
	return fv_result;
}
int hopper_device::cctalk_write_data_block(char addr, char data_block_nr, char nr_of_bytes,  char vp_data[])
{
	int i1;
	//int fv_result;
	Buf_Tx[0] = addr;
	Buf_Tx[1] = (byte)(nr_of_bytes + 1);
	Buf_Tx[2] = 0x01;
	Buf_Tx[3] = 0xA1;
	Buf_Tx[4] = data_block_nr;
	for(i1 = 0; i1 <= nr_of_bytes - 1; i1++ )
	  Buf_Tx[i1 + 5] = vp_data[i1];
	return cctalk_write_n_bytes(Buf_Tx, Buf_Rx, (byte)(5 + nr_of_bytes));
}

__declspec(dllexport) int __stdcall hopper_init(void)
{
	char log_str[15];
	hopper_device_inst = new hopper_device();
	hopper_is_created = true;
	char ret_str[63];
	int build_year = 0;
	int build_month = 0;
	int build_day = 0;
	int build_hour = 0;
	int build_min = 0;
	char build_month_str[4];
	char version_str[15];
	sscanf(__DATE__, "%s %d %d", build_month_str, &build_day, &build_year);
	//strncpy(build_month_str, __DATE__, 3);
	if (!strcmp(build_month_str, "Jan"))
		build_month = 1;
	if (!strcmp(build_month_str, "Feb"))
		build_month = 2;
	if (!strcmp(build_month_str, "Mar"))
		build_month = 3;
	if (!strcmp(build_month_str, "Apr"))
		build_month = 4;
	if (!strcmp(build_month_str, "May"))
		build_month = 5;
	if (!strcmp(build_month_str, "Jun"))
		build_month = 6;
	if (!strcmp(build_month_str, "Jul"))
		build_month = 7;
	if (!strcmp(build_month_str, "Aug"))
		build_month = 8;
	if (!strcmp(build_month_str, "Sep"))
		build_month = 9;
	if (!strcmp(build_month_str, "Oct"))
		build_month = 10;
	if (!strcmp(build_month_str, "Nov"))
		build_month = 11;
	if (!strcmp(build_month_str, "Dec"))
		build_month = 12;
	sscanf(__TIME__, "%d:%d", &build_hour, &build_min);
	sprintf(version_str, "%04d%02d%02d%02d%02d", build_year, build_month, build_day, build_hour, build_min);

	sprintf(ret_str, "-> door_control_init, dll version %s", version_str);
	hopper_device_inst->log_add_str(ret_str);
	if (hopper_device_inst != 0)
	{
		strcpy(log_str, "<- OK");
		hopper_device_inst->log_add_str(log_str);
		return 0;
	}
	else
	{
		strcpy(log_str, "<- Failed");
		hopper_device_inst->log_add_str(log_str);
		return 1;
	}
}
__declspec(dllexport) int __stdcall hopper_init_prepare_mode_d2xx(int mode, int inp_par, int port_No, char * vpPort_name)
{
	int ret_val = 0;
	int res_var = 0;
	char buf_str[63];
	cout << " hopper_init_prepare_mode_d2xx:" << endl;
	cout << "  mode " << mode << endl;
	cout << "  inp_par " << inp_par << endl;
	cout << "  port_No " << port_No << endl;
	cout << "  vpPort_name " << vpPort_name << endl;
	res_var = hopper_init();
	sprintf(buf_str, "hopper_init_prepare_mode_d2xx %d %d %d %s", mode, inp_par, port_No, vpPort_name);
	hopper_device_inst->log_add_str(buf_str);
	//hopper_device_inst->log_add_str("hopper_init_prepare_mode_d2xx");
	if (res_var == 0)
	{
		res_var |= hopper_set_mode(mode);
		cout << "hopper_init_prepare_mode_d2xx: hopper_set_mode(" << mode << ") " << res_var << endl;
		if (res_var == 0)
		{
			res_var |= hopper_prepare(inp_par, port_No, vpPort_name);
			cout << "hopper_init_prepare_mode_d2xx: hopper_prepare(...) " << res_var << endl;
			if (res_var == 0)
			{
				hopper_device_inst->log_add_str("hopper_init_prepare_mode_d2xx OK");
			}
			else
			{
				ret_val |= res_var << 8;
			}
		}
		else
		{
			ret_val |= 1 << 1;
		}
	}
	else
	{
		ret_val |= 1 << 0;
	}
	return ret_val;
}

__declspec(dllexport) int __stdcall hopper_init_prepare_mode_d2xx_portNo(int mode, int port_No)
{
	int ret_val = 0;
	char buf_str[63];
	//ret_val = hopper_init_prepare_mode_d2xx(mode, 1, port_No, "");
	ret_val = hopper_init_prepare_mode_d2xx(mode, 1, port_No, "");
	sprintf(buf_str, "hopper_init_prepare_mode_d2xx_portNo mode %d port_No %d", mode, port_No);
	hopper_device_inst->log_add_str(buf_str);
	return ret_val;
}

__declspec(dllexport) int __stdcall hopper_port_open(char * vpPort_name)
{
    int ret_var = 0;
    int res_var = 0;
	char ret_str[63];
    if (hopper_is_created)
    {
    	if (vpPort_name[0] != '\0')
    		strcpy(hopper_device_inst->ser_port_name, vpPort_name);
    	//ret_var = hopper_device_inst->set_name(vpPort_name);
    	ret_var = hopper_device_inst->open_ser();
		sprintf(ret_str, "-  hopper_ser_open %d", ret_var);
		hopper_device_inst->log_add_str(ret_str);
		if (ret_var != 0 )
		{
			res_var = hopper_device_inst->port_close();
			sprintf(ret_str, "-  hopper_ser_open port_close %d", res_var);
			hopper_device_inst->log_add_str(ret_str);
			res_var = hopper_device_inst->open_d2xx_dll();
			sprintf(ret_str, "-  hopper_ser_open open_d2xx_dll %d", res_var);
			hopper_device_inst->log_add_str(ret_str);
			res_var = hopper_device_inst->open_d2xx();
			sprintf(ret_str, "-  hopper_ser_open open_d2xx %d", res_var);
			hopper_device_inst->log_add_str(ret_str);
			res_var = FT_Close(hopper_device_inst->ft_handle);
			sprintf(ret_str, "-  hopper_ser_open FT_Close %d", res_var);
			hopper_device_inst->log_add_str(ret_str);
			res_var = hopper_device_inst->open_ser();
			sprintf(ret_str, "-  hopper_ser_open open_ser %d", res_var);
			hopper_device_inst->log_add_str(ret_str);
			ret_var = res_var;
		}
    }
    else
    	ret_var = 255;
	return ret_var;
}

__declspec(dllexport) int __stdcall hopper_d2xx_open(void)
{
    int ret_var = 0;
    int res_var = 0;
	char ret_str[63];
    if (hopper_is_created)
    {
    	//cout << "hopper_d2xx_open vpPort_name " << vpPort_name << endl;
    	/*if (vpPort_name[0] != '\0')
    	{
    		strcpy(hopper_device_inst->ser_port_name, vpPort_name);
    		hopper_device_inst->ser_port_No = hopper_device_inst->get_ser_No(hopper_device_inst->ser_port_name);
    		cout << " hopper_d2xx_open: get_ser_No(" << hopper_device_inst->ser_port_name << ") is " << hopper_device_inst->ser_port_No << endl;
    	}*/
    	cout << " hopper_d2xx_open: ser_port_No is " << hopper_device_inst->ser_port_No << endl;
    	//ret_var = hopper_device_inst->set_name(vpPort_name);
    	res_var = hopper_device_inst->open_d2xx_dll();
		sprintf(ret_str, "-  hopper_open_d2xx_dll %d", res_var);
		cout << ret_str << endl;
		hopper_device_inst->log_add_str(ret_str);
		res_var = hopper_device_inst->open_d2xx();
		sprintf(ret_str, "-  hopper_open_d2xx %d", res_var);
		cout << ret_str << endl;
		hopper_device_inst->log_add_str(ret_str);
		ret_var = res_var;
    }
    else
    	ret_var = 255;
	return ret_var;
}

__declspec(dllexport) int __stdcall hopper_close(void)
{
	char log_str[63];
	int ret_val;
	strcpy(log_str, "-- hopper_finish");
	if(hopper_is_created)
	{
		hopper_device_inst->log_add_str(log_str);
		hopper_device_inst->~hopper_device();
		hopper_is_created = false;
		ret_val = 0;
	}
	else
		ret_val = 255;
	return ret_val;
}
__declspec(dllexport) int __stdcall hopper_send_simple_poll(char addr)
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_send_simple_pool(addr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_address_poll(char * addr)
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_address_pool(addr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_request_comms_revision(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_request_comms_revision(addr, vp_byte_arr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_request_comm_status_variables(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_request_comms_status_variables(addr, vp_byte_arr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_clear_comms_variables(char addr)
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_clear_comms_variables(addr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_reset_device(char addr)
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_reset_device(addr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_request_manufacturer_id(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
	{
	  return hopper_device_inst->cctalk_request_manufacturer_id(addr, vp_byte_arr);
	}
	else
	  return 255;
}
__declspec(dllexport) int __stdcall hopper_request_equipment_category_id(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
	{
		return hopper_device_inst->cctalk_request_equipment_category_id(addr, vp_byte_arr);
	}
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_request_product_code(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
	{
		return hopper_device_inst->cctalk_request_product_code(addr, vp_byte_arr);
	}
	else
		return 255;
}
// Get serial number
// vp_byte_arr[0] is number of returned bytes of the serial number
// vp_byte_arr[1...] - considers bytes of the serial number
// normally serial number is 3 bytes length
__declspec(dllexport) int __stdcall hopper_request_serial_nr(char addr, char vp_byte_arr[])
{
if(hopper_is_created)
	return hopper_device_inst->cctalk_request_serial_nr(addr, vp_byte_arr);
else
	return 255;
}
__declspec(dllexport) int __stdcall hopper_request_software_revision(char addr, char vp_byte_arr[])
{
if(hopper_is_created)
	return hopper_device_inst->cctalk_request_software_revision(addr, vp_byte_arr);
else
	return 255;
}
__declspec(dllexport) int __stdcall hopper_request_data_storage_availability(char addr, char vp_byte_arr[])
{
if(hopper_is_created)
	return hopper_device_inst->cctalk_request_data_storage_availability(addr, vp_byte_arr);
else
	return 255;
}
__declspec(dllexport) int __stdcall hopper_request_build_code(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_request_build_code(addr, vp_byte_arr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_request_address_mode(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_request_address_mode(addr, vp_byte_arr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_enter_PIN_number(char addr, char vp_PIN_number[])
{
if(hopper_is_created) {
	return hopper_device_inst->cctalk_enter_PIN_number(addr, vp_PIN_number);
}else
	return 255;
}
__declspec(dllexport) int __stdcall hopper_enter_new_PIN_number(char addr, char vp_PIN_number[])
{
if(hopper_is_created) {
  return hopper_device_inst->cctalk_enter_new_PIN_number(addr, vp_PIN_number);
}else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_modify_variable_settings(char addr, char vp_variable_settings[])
{
if(hopper_is_created)
{
	return hopper_device_inst->cctalk_modify_variable_settings(addr, vp_variable_settings);
}
else
	return 255;
}
__declspec(dllexport) int __stdcall hopper_request_variable_settings(char addr, char vp_variable_settings[])
{
if(hopper_is_created) {
  return hopper_device_inst->cctalk_request_variable_settings(addr, vp_variable_settings);
}else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_test_hopper(char addr, char vp_hopper_registers[])
{
if(hopper_is_created)
{
  return hopper_device_inst->cctalk_test_hopper(addr, vp_hopper_registers);
}else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_request_status(char addr, char vp_byte_arr[])
{
if(hopper_is_created)
{
  return hopper_device_inst->cctalk_hopper_status(addr, vp_byte_arr);
}else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_emergency_stop(char addr, char vp_byte_arr[])
{
if(hopper_is_created)
{
  return hopper_device_inst->cctalk_emergency_stop(addr, vp_byte_arr);
}else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_empty_hopper(char addr, int coins_to_put)
{
if(hopper_is_created)
  return hopper_device_inst->cctalk_empty_hopper(addr, hopper_device_inst->buf_RxTx_arr, coins_to_put);
			//.cctalk_Empty_Hopper(addr, hopper_device_inst->buf_RxTx_arr, coins_to_put);
else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_request_payout_hi_lo_status(char addr, char vp_byte_arr[])
{
if(hopper_is_created) {
  return hopper_device_inst->cctalk_request_payout_hi_lo_status(addr, vp_byte_arr);
}else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_request_payout_hi_status(char addr, bool * out_bool)
{
	int fv_result;
	if(hopper_is_created)
	{
		fv_result = hopper_device_inst->cctalk_request_payout_hi_lo_status(addr, hopper_device_inst->buf_RxTx_arr);
		*out_bool = !((hopper_device_inst->buf_RxTx_arr[1] & 0x02) == 0);
	}
	else
		fv_result = 255;
	return fv_result;
}
__declspec(dllexport) int __stdcall hopper_request_payout_lo_status(char addr, bool * out_bool)
{
	int fv_result;
	if(hopper_is_created)
	{
		fv_result = hopper_device_inst->cctalk_request_payout_hi_lo_status(addr, hopper_device_inst->buf_RxTx_arr);
		*out_bool = !((hopper_device_inst->buf_RxTx_arr[1] & 0x01) == 0);
	}
	else
		fv_result = 255;
	return fv_result;
}
// Enable dispensing
__declspec(dllexport) int __stdcall hopper_enable(char addr)
{
if(hopper_is_created)
  return hopper_device_inst->cctalk_enable_hopper(addr);
else
  return 255;
}
// Disable dispensing
__declspec(dllexport) int __stdcall hopper_disable(char addr)
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_disable_hopper(addr);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_pump_RNG(char addr, char vp_RNG[])
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_pump_RNG(addr, vp_RNG);
	else
		return 255;
}
__declspec(dllexport) int __stdcall hopper_request_cipher_Key(char addr, char vp_byte_arr[])
{
	if(hopper_is_created)
		return hopper_device_inst->cctalk_request_cipher_key(addr, vp_byte_arr);
	else
		return 255;
}
// Dispense n coins
__declspec(dllexport) int __stdcall hopper_dispense_coins(byte addr, int coins_to_put)
{
if(hopper_is_created)
  return hopper_device_inst->cctalk_dispense_coins(addr, hopper_device_inst->buf_RxTx_arr, coins_to_put);
else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_request_dispense_count(char addr, char vp_byte_arr[])
{
if(hopper_is_created)
  return hopper_device_inst->cctalk_request_hopper_dispense_count(addr, hopper_device_inst->buf_RxTx_arr);
else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_read_data_block(char addr, byte data_block_nr, char vp_byte_arr[])
{
if(hopper_is_created)
  return hopper_device_inst->cctalk_read_data_block(addr, data_block_nr, hopper_device_inst->buf_RxTx_arr);
else
  return 255;
}
__declspec(dllexport) int __stdcall hopper_write_data_block(char addr, byte data_block_nr, byte nr_of_bytes, char vp_byte_arr[])
{
if(hopper_is_created)
  return hopper_device_inst->cctalk_write_data_block(addr, nr_of_bytes, data_block_nr, hopper_device_inst->buf_RxTx_arr);
else
  return 255;
}

__declspec(dllexport) int __stdcall hopper_set_mode(char dev_interface_mode_inp)
{
	int ret_val = 0;
	if(hopper_is_created)
	{
		hopper_device_inst->dev_interface_mode = dev_interface_mode_inp;
	}
	else ret_val = 255;
	return ret_val;
}
__declspec(dllexport) int __stdcall hopper_prepare_addr(char addr)
{
	//int f_result;
	int fv_intern_result;
	int fv_result;
	char buf_arr[16];// = new byte[16];
	if(hopper_is_created)
	{
		cout << "cctalk_reset_device...";
		fv_intern_result = hopper_device_inst->cctalk_reset_device(addr);
		cout << fv_intern_result << endl;
		if (fv_intern_result == 0)
		{
			Sleep(500);
			cout << "cctalk_send_simple_pool...";
			fv_intern_result = hopper_device_inst->cctalk_send_simple_pool(addr);
			cout << fv_intern_result << endl;
			if (fv_intern_result == 0)
			{
				cout << "cctalk_request_serial_nr...";
				fv_intern_result = hopper_device_inst->cctalk_request_serial_nr(addr, buf_arr);
				cout << fv_intern_result << endl;
				cout << "cctalk_enable_hopper_device_inst->..";
				fv_intern_result = hopper_device_inst->cctalk_enable_hopper(addr);
				cout << fv_intern_result << endl;
				fv_result = 0;
			}
			else
				fv_result = fv_intern_result;
		}
		else
		{
			//Console.WriteLine("Hopper_prepare - Reset hopper addr {0} failed", addr);
			fv_result = fv_intern_result;
		}
	}
	else
		fv_result = 255;
	return fv_result;
}
__declspec(dllexport) int __stdcall hopper_prepare(int inp_par, int port_No, char * vp_Port_name)
{
	int fv_result;
	int fv_intern_result;
	char log_str[63];
	int res_var = 0;
	switch (inp_par)
	{
	case 1:
		hopper_device_inst->ser_port_No = port_No;
		break;
	case 2:
		strcpy(hopper_device_inst->ser_port_name, vp_Port_name);
		hopper_device_inst->ser_port_No = hopper_device_inst->get_ser_No(hopper_device_inst->ser_port_name);
		break;
	default:
		//hopper_device_inst->ser_port_No = port_No;
		//strcpy(hopper_device_inst->ser_port_name, vp_Port_name);
		break;
	}
	//if (vpPort_name[0] != '\0')
	//	strcpy(hopper_device_inst->ser_port_name, vpPort_name);
	if(hopper_is_created) {
		fv_intern_result = 0;
		//cout << "hopper_port_open...";
		switch (hopper_device_inst->dev_interface_mode)
		{
		case 1:
			fv_intern_result = hopper_port_open(hopper_device_inst->ser_port_name);
			break;
		case 2:
			//fv_intern_result = hopper_d2xx_open(hopper_device_inst->ser_port_name);
			fv_intern_result = hopper_d2xx_open();
			break;
		}
		cout << "ready " << fv_intern_result << endl;
		if (fv_intern_result == 0)
		{
			//cout << "hopper_prepare_addr(3)...";
			res_var = hopper_prepare_addr(3);
			if (res_var != 0) fv_intern_result = fv_intern_result | 0x01;
			cout << "hopper_prepare_addr(3) " <<  res_var << endl;
			//cout << "ready " << fv_intern_result << endl;
			//cout << "hopper_prepare_addr(4)...";
			res_var = hopper_prepare_addr(4);
			if (res_var != 0) fv_intern_result = fv_intern_result | 0x02;
			cout << "hopper_prepare_addr(4) " <<  res_var << endl;
			//cout << "ready " << fv_intern_result << endl;
		}
		else
			fv_intern_result = (0x04) | (fv_intern_result << 4);
		fv_result = fv_intern_result;
	}
	else
	{
		cout << "hopper is not created" << endl;
		fv_result = 255;
	}
	return fv_result;
}
__declspec(dllexport) int __stdcall hopper_put_coins(char addr, int Coins_count)
{
	char buf_arr[16];// = new byte[16];
	if(hopper_is_created)
	{
	  return hopper_device_inst->cctalk_dispense_coins(addr , buf_arr, Coins_count);
	}
	else
	  return 255;
}
__declspec(dllexport) int __stdcall hopper_put_coins_ack(char addr, int Coins_count,
								int * Coins_rem, int * Coins_paid, int * Coins_unpaid)
{
	char buf_arr[16];// = new byte[16];
	int cycle_counter;
	int cycle_counter_paid_changed;
	//int f_return;
	int fv_result;
	const int pay_size_max = 100;
	int pay_paid = 0;
	int pay_cycle_to_pay = 0;
	int pay_remained = Coins_count;
	int Status_Payout_coins_remaining;
	int Status_Coins_unpaid;
	int Status_Coins_paid;
	int Status_Coins_paid_prev;
	int err = 0;
	if(hopper_is_created)
	{
		while ((pay_paid < Coins_count) && (err == 0))
		{
			pay_cycle_to_pay = (pay_size_max > pay_remained) ? pay_remained : pay_size_max;
			fv_result = hopper_device_inst->cctalk_dispense_coins(addr , buf_arr, pay_cycle_to_pay);
			if (fv_result != 0)
				return fv_result;
			cycle_counter = 0;
			Status_Coins_paid_prev = 0;
			cycle_counter_paid_changed = 0;
			Status_Coins_paid = pay_cycle_to_pay;
			cycle_counter = 0;
			do
			{
				cycle_counter++;
				Sleep(500);//System.Threading.Thread.Sleep(500);
				//f_return = hopper_device_inst->cctalk_Hopper_status(addr, buf_arr);
				fv_result = hopper_device_inst->cctalk_hopper_status(addr, buf_arr);
				//Console.WriteLine("hopper_device_inst->cctalk_Hopper_status {0} rem {1} paid {2} unpaid {3}",
				//                  fv_result, buf_arr[2], buf_arr[3], buf_arr[4]);
				if (fv_result != 0)
					return fv_result;
				Status_Payout_coins_remaining = buf_arr[2];
				if (Status_Coins_paid_prev != Status_Coins_paid)
					cycle_counter_paid_changed = cycle_counter;
				Status_Coins_paid_prev = Status_Coins_paid;
				Status_Coins_paid = buf_arr[3];
				Status_Coins_unpaid = buf_arr[4];
				/*Console.WriteLine("cycle {0} ; rem {1} ; paid {2} ; unpaid {3}",
								  cycle_counter,
								  Status_Payout_coins_remaining,
								  Status_Coins_paid,
								  Status_Coins_unpaid
								  );*/
				if((cycle_counter - cycle_counter_paid_changed) > 8)
					err = 1;
			}
			while(!((Status_Payout_coins_remaining == 0) || (err > 0)));
			//until((Status_Payout_coins_remaining = 0) or ((cycle_counter - cycle_counter_paid_changed) > 60));
			pay_paid += Status_Coins_paid;
			pay_remained -= Status_Coins_paid;
			cout << " * : Status_Coins_paid " << Status_Coins_paid << endl;
			cout << " * : Status_Coins_unpaid " << Status_Coins_unpaid << endl;
			cout << " * : Status_Payout_coins_remaining " << Status_Payout_coins_remaining << endl;
			cout << " * pay_paid: " << pay_paid << endl;
			cout << " * pay_remained: " << pay_remained << endl;
		}
		//*Coins_rem = Status_Payout_coins_remaining;
		//*Coins_paid = Status_Coins_paid;
		//*Coins_unpaid = Status_Coins_unpaid;
		*Coins_rem = pay_remained + Status_Payout_coins_remaining;
		*Coins_paid = pay_paid;
		*Coins_unpaid = Status_Coins_unpaid;
		cout << "hopper_put_coins_ack("<< static_cast<int>(addr) << ", " << Coins_count << "):" << fv_result << ", "
				<< "Coins_rem: " << static_cast<int>(*Coins_rem) << "; "
				<< "Coins_paid: " << static_cast<int>(*Coins_paid) << "; "
				<< "Coins_unpaid: " << static_cast<int>(*Coins_unpaid) << ". "
				<< "pay_remained: " << pay_remained << ". "
				<< endl;
	}
	else
		fv_result = 255;
	//Console.WriteLine("\nhopper_device_inst->cctalk_Dispense_coins {0}", fv_result);
	return fv_result;
}
__declspec(dllexport) bool __stdcall hopper_get_high_sensor(char addr)
{
	//int f_result;
	bool fv_result;
	char buf_arr[16];// = new byte[16];
	if(hopper_is_created) {
		fv_result = false;
	hopper_device_inst->cctalk_request_payout_hi_lo_status(addr, buf_arr);
	//buf_arr[1] = 0x00; //ans 0
	//buf_arr[1] = 0x02; //ans -1
	if ((buf_arr[1] & 0x02) != 0 )
		fv_result = true;
	else
		fv_result = false;
	//Hopper_Get_High_sensor = false; //0
	//Hopper_Get_High_sensor = true; //-1
	}
	else
		fv_result = false;
	return fv_result;
}
__declspec(dllexport) bool __stdcall hopper_get_low_sensor(char addr)
{
	bool fv_result;
	char buf_arr[16];// = new byte[16];
	if(hopper_is_created) {
		fv_result = false;
	hopper_device_inst->cctalk_request_payout_hi_lo_status(addr, buf_arr);
	//buf_arr[1] = 0x01;
	if ((buf_arr[1] & 0x01) != 0)
		fv_result = true;
	else
		fv_result = false;
	}else
		fv_result = false;
	return fv_result;
}
__declspec(dllexport) int __stdcall hopper_get_error(byte addr)
{
if(hopper_is_created)
  return hopper_device_inst->cctalk_send_simple_pool(addr);
else
  return 255;
}

/*int main()
{
	return 0;
}*/
